package com.gwl.concurrent.interrupt;

import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import static java.lang.System.out;

class SleepBlocked implements Runnable {
	@Override
	public void run() {
		try {
			TimeUnit.SECONDS.sleep(100);
		} catch (InterruptedException e) { 
			out.println("InterruptedException"); 
		} 
		out.println("Exiting SleepBlock.run()"); 
	}
} 
class IOBlocked implements Runnable {
	private InputStream in; 
	public IOBlocked(InputStream in) { 
		this.in = in; 
	}
	@Override
	public void run() { 
		try { 
			out.println("Waiting for read():"); 
			in.read();
		} catch (IOException e) { 
			if(Thread.currentThread().isInterrupted()) { 
				out.println("Interrupted from blocked I/O"); 
			} else { 
				throw new RuntimeException(e); 
			}
		} 
		out.println("Exiting IOBlocked.run()"); 
	} 
}

class SynchronizedBlocked implements Runnable {

	private synchronized void f() { 
		while(true)  //Never releases lock
			Thread.yield(); 
	}

	public SynchronizedBlocked() { 
		new Thread() {
			@Override
			public void run() {
				f();  //Lock acquired by this thread
			}
		}.start(); 
	}
	
	@Override
	public void run() {
		//Try to call f()
		f(); 
		out.println("Exiting SynchronizedBlocked.run()"); 
	} 
}
public class Interrupting { 
	private static final ExecutorService exec = Executors.newCachedThreadPool(); 
	static void test(Runnable r) throws InterruptedException { 
		Future<?> future = exec.submit(r); 
		TimeUnit.MILLISECONDS.sleep(300); 
		out.println("Interrupting " + r.getClass().getName()); 
		future.cancel(true); 
		out.println("Interrupt send to " + r.getClass().getName()); 
	} 
	public static void main(String[] args) throws InterruptedException {
		test(new SleepBlocked()); 
		test(new IOBlocked(System.in)); 
		test(new SynchronizedBlocked()); 
		TimeUnit.MILLISECONDS.sleep(300); 
		out.println("Aborting with System.exit(0)"); 
		System.exit(0);  //since last 2 interrupts failed
	}
}
